﻿#include "Logger.h"

// 实例化 全局对象
Logger g_Logger(L"Hook.log", false, false); // 默认不显示编码标记和时间戳

#ifdef DEBUG_MODE
Logger::Logger(const std::wstring& filePath, bool showEncodingTags, bool showTimestamp)
    : m_logFilePath(filePath),
    m_showEncodingTags(showEncodingTags),
    m_showTimestamp(showTimestamp)
{
    std::lock_guard<std::mutex> lock(m_logMutex);
    m_logFile = std::make_unique<std::ofstream>();
    m_logFile->open(m_logFilePath, std::ios::out | std::ios::trunc);

    if (m_logFile->is_open()) {
        // 写入UTF-8 BOM
        const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
        m_logFile->write(reinterpret_cast<const char*>(bom), sizeof(bom));

        // 写入初始信息
        SYSTEMTIME st;
        GetLocalTime(&st);
        *m_logFile << u8"=== 日志开始 ===\n"
            << u8"创建时间: " << st.wYear << "/" << st.wMonth << "/" << st.wDay << " "
            << st.wHour << ":" << st.wMinute << ":" << st.wSecond << "\n"
            << u8"日志路径: " << StringUtils::WideCharToUTF8(m_logFilePath.c_str()) << "\n";
        m_logFile->flush();
    }
}

Logger::~Logger() {
    std::lock_guard<std::mutex> lock(m_logMutex);
    if (m_logFile && m_logFile->is_open()) {
        *m_logFile << u8"=== 日志结束 ===\n";
        m_logFile->close();
        m_logFile.reset();
    }
}

void Logger::SetShowEncodingTags(bool show) {
    std::lock_guard<std::mutex> lock(m_logMutex);
    m_showEncodingTags = show;
}

void Logger::SetShowTimestamp(bool show) {
    std::lock_guard<std::mutex> lock(m_logMutex);
    m_showTimestamp = show;
}

std::string Logger::GetTimestamp() {
    SYSTEMTIME st;
    GetLocalTime(&st);

    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
        st.wYear, st.wMonth, st.wDay,
        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);

    return buffer;
}

Logger::ArgumentWrapper::ArgumentWrapper(const char* s) :
    type(DataType::String),
    stringValue(EnsureUTF8(s, false)),
    encodingTag(GetEncodingTag(s)) {
}

Logger::ArgumentWrapper::ArgumentWrapper(const wchar_t* s) :
    type(DataType::WideString),
    wideValue(s),
    stringValue(StringUtils::WideCharToUTF8(s)),
    encodingTag(GetWideEncodingTag()) {
}

Logger::ArgumentWrapper::ArgumentWrapper(const std::string& s) :
    type(DataType::String),
    stringValue(EnsureUTF8(s.c_str(), false)),
    encodingTag(GetEncodingTag(s.c_str())) {
}

Logger::ArgumentWrapper::ArgumentWrapper(const std::wstring& ws) :
    type(DataType::WideString),
    wideValue(ws),
    stringValue(StringUtils::WideCharToUTF8(ws.c_str())),
    encodingTag(GetWideEncodingTag()) {
}

Logger::ArgumentWrapper::ArgumentWrapper(char c) :
    type(DataType::Integer),
    intValue(c) {
}

Logger::ArgumentWrapper::ArgumentWrapper(wchar_t wc) :
    type(DataType::WideString),
    wideValue(1, wc),
    stringValue(FormatWideChar(wc)),
    encodingTag(GetWideEncodingTag()) {
}

std::string Logger::EnsureUTF8(const char* str, bool skipTag) {
    if (!str || *str == '\0') return "";
    if (StringUtils::IsValidUTF8(str)) return str;
    return StringUtils::GBKToUTF8(str);
}

std::string Logger::GetWideEncodingTag() {
    return "[UTF-16]";
}

std::string Logger::GetEncodingTag(const char* str) {
    return (StringUtils::IsValidUTF8(str) ? "[UTF-8]" : "[ANSI]");
}

std::string Logger::EscapeSpecialCharacters(const std::string& str) {
    static const std::unordered_map<char, std::string> escapeSequences = {
        {'\n', "\\n"}, {'\t', "\\t"}, {'\r', "\\r"},
        {'\0', "\\0"}, {'\a', "\\a"}, {'\b', "\\b"},
        {'\f', "\\f"}, {'\v', "\\v"}, {'\\', "\\\\"}
    };

    std::string result;
    result.reserve(str.size() + str.size() / 5);  // 预留额外空间

    for (unsigned char c : str) {
        if (auto it = escapeSequences.find(c); it != escapeSequences.end()) {
            result += it->second;
        }
        else if (c < 32 || c == 127) {
            char hex[5];
            snprintf(hex, sizeof(hex), "\\x%02X", c);
            result += hex;
        }
        else {
            result += c;
        }
    }
    return result;
}

//std::string Logger::GetTimestamp() {
//    SYSTEMTIME st;
//    GetLocalTime(&st);
//
//    char buffer[32];
//    snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
//        st.wYear, st.wMonth, st.wDay,
//        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
//
//    return buffer;
//}

std::string Logger::FormatMessage(const char* format, const std::vector<ArgumentWrapper>& args) const {
    std::string result;
    size_t argIndex = 0;
    const char* ptr = format;

    while (*ptr) {
        if (*ptr == '%' && *(ptr + 1) != '\0') {
            if (*(ptr + 1) == '%') {
                result += '%';
                ptr += 2;
                continue;
            }

            const char* specStart = ptr++;
            bool leftAlign = false, showSign = false, spaceSign = false;
            bool alternateForm = false, zeroPad = false;

            // 解析标志字符
            while (*ptr == '-' || *ptr == '+' || *ptr == ' ' || *ptr == '#' || *ptr == '0') {
                switch (*ptr) {
                case '-': leftAlign = true; break;
                case '+': showSign = true; break;
                case ' ': spaceSign = true; break;
                case '#': alternateForm = true; break;
                case '0': zeroPad = true; break;
                }
                ptr++;
            }

            // 解析宽度
            int width = 0;
            bool dynamicWidth = (*ptr == '*');
            if (dynamicWidth) {
                ptr++;
            }
            else {
                while (std::isdigit(static_cast<unsigned char>(*ptr))) {
                    width = width * 10 + (*ptr - '0');
                    ptr++;
                }
            }

            // 解析精度
            int precision = -1;
            bool dynamicPrecision = false;
            if (*ptr == '.') {
                ptr++;
                if (*ptr == '*') {
                    dynamicPrecision = true;
                    ptr++;
                }
                else {
                    precision = 0;
                    while (std::isdigit(static_cast<unsigned char>(*ptr))) {
                        precision = precision * 10 + (*ptr - '0');
                        ptr++;
                    }
                }
            }

            // 解析长度修饰符
            enum LengthModifier { None, HH, H, L, LL, Z, J, T } lengthMod = None;
            if (*ptr == 'h') {
                ptr++;
                if (*ptr == 'h') { lengthMod = HH; ptr++; }
                else lengthMod = H;
            }
            else if (*ptr == 'l') {
                ptr++;
                if (*ptr == 'l') { lengthMod = LL; ptr++; }
                else lengthMod = L;
            }
            else if (*ptr == 'z') { lengthMod = Z; ptr++; }
            else if (*ptr == 'j') { lengthMod = J; ptr++; }
            else if (*ptr == 't') { lengthMod = T; ptr++; }
            else if (*ptr == 'L') { lengthMod = L; ptr++; }

            char specifier = *ptr++;
            if (argIndex >= args.size()) {
                result.append(specStart, ptr);
                continue;
            }

            // 处理动态宽度
            if (dynamicWidth) {
                const ArgumentWrapper& warg = args[argIndex++];
                if (warg.type == ArgumentWrapper::DataType::Integer) {
                    width = static_cast<int>(warg.intValue);
                    if (width < 0) { leftAlign = true; width = -width; }
                }
                else if (warg.type == ArgumentWrapper::DataType::Unsigned) {
                    width = static_cast<int>(warg.uintValue);
                }
            }

            // 处理动态精度
            if (dynamicPrecision) {
                const ArgumentWrapper& parg = args[argIndex++];
                if (parg.type == ArgumentWrapper::DataType::Integer) {
                    precision = static_cast<int>(parg.intValue);
                }
                else if (parg.type == ArgumentWrapper::DataType::Unsigned) {
                    precision = static_cast<int>(parg.uintValue);
                }
                if (precision < 0) precision = -1;
            }

            const ArgumentWrapper& arg = args[argIndex++];
            std::string formattedArg;

            // 根据格式说明符处理参数
            switch (specifier) {
            case 's':
                if (arg.type == ArgumentWrapper::DataType::WideString) {
                    formattedArg = EscapeSpecialCharacters(StringUtils::WideCharToUTF8(arg.wideValue.c_str()));
                }
                else {
                    formattedArg = EscapeSpecialCharacters(arg.stringValue);
                }
                if (m_showEncodingTags && !arg.encodingTag.empty()) {
                    formattedArg += " " + arg.encodingTag;
                }
                break;

            case 'c':
                if (arg.type == ArgumentWrapper::DataType::WideString) {
                    formattedArg = FormatWideChar(arg.wideValue[0]);
                }
                else {
                    formattedArg = FormatChar(static_cast<char>(arg.intValue));
                }
                break;

            case 'd': case 'i': {
                int64_t val = (arg.type == ArgumentWrapper::DataType::Integer) ? arg.intValue :
                    (arg.type == ArgumentWrapper::DataType::Unsigned) ? static_cast<int64_t>(arg.uintValue) :
                    (arg.type == ArgumentWrapper::DataType::Float) ? static_cast<int64_t>(arg.floatValue) : 0;
                if (lengthMod == HH) val = static_cast<signed char>(val);
                else if (lengthMod == H) val = static_cast<short>(val);
                formattedArg = FormatInteger(val, width, zeroPad, showSign, spaceSign);
                break;
            }

            case 'u': {
                uint64_t val = (arg.type == ArgumentWrapper::DataType::Unsigned) ? arg.uintValue :
                    static_cast<uint64_t>(arg.intValue);
                if (lengthMod == HH) val = static_cast<unsigned char>(val);
                else if (lengthMod == H) val = static_cast<unsigned short>(val);
                formattedArg = FormatUnsigned(val, width, zeroPad);
                break;
            }

            case 'o': {
                uint64_t val = (arg.type == ArgumentWrapper::DataType::Unsigned) ? arg.uintValue :
                    static_cast<uint64_t>(arg.intValue);
                if (lengthMod == HH) val = static_cast<unsigned char>(val);
                else if (lengthMod == H) val = static_cast<unsigned short>(val);
                formattedArg = FormatOctal(val, width, zeroPad, alternateForm);
                break;
            }

            case 'x': case 'X': {
                uint64_t val = (arg.type == ArgumentWrapper::DataType::Unsigned) ? arg.uintValue :
                    static_cast<uint64_t>(arg.intValue);
                if (lengthMod == HH) val = static_cast<unsigned char>(val);
                else if (lengthMod == H) val = static_cast<unsigned short>(val);
                formattedArg = FormatHex(val, width, zeroPad, alternateForm, specifier == 'X');
                break;
            }

            case 'f': case 'F': {
                double val = (arg.type == ArgumentWrapper::DataType::Float) ? arg.floatValue :
                    (arg.type == ArgumentWrapper::DataType::Integer) ? static_cast<double>(arg.intValue) :
                    static_cast<double>(arg.uintValue);
                formattedArg = FormatFloat(val, precision, width, zeroPad, showSign, spaceSign);
                break;
            }

            case 'e': case 'E': {
                double val = (arg.type == ArgumentWrapper::DataType::Float) ? arg.floatValue :
                    (arg.type == ArgumentWrapper::DataType::Integer) ? static_cast<double>(arg.intValue) :
                    static_cast<double>(arg.uintValue);
                formattedArg = FormatScientific(val, precision, width, zeroPad, showSign, spaceSign, specifier == 'E');
                break;
            }

            case 'g': case 'G': {
                double val = (arg.type == ArgumentWrapper::DataType::Float) ? arg.floatValue :
                    (arg.type == ArgumentWrapper::DataType::Integer) ? static_cast<double>(arg.intValue) :
                    static_cast<double>(arg.uintValue);
                formattedArg = FormatGeneral(val, precision, width, zeroPad, showSign, spaceSign, specifier == 'G');
                break;
            }

            case 'a': case 'A': {
                double val = (arg.type == ArgumentWrapper::DataType::Float) ? arg.floatValue :
                    (arg.type == ArgumentWrapper::DataType::Integer) ? static_cast<double>(arg.intValue) :
                    static_cast<double>(arg.uintValue);
                char buffer[128];
                snprintf(buffer, sizeof(buffer), "%a", val);
                formattedArg = buffer;
                break;
            }

            case 'p': {
                if (arg.ptrValue == nullptr) {
                    formattedArg = "nullptr";
                }
                else {
                    if (arg.type == ArgumentWrapper::DataType::FunctionPtr) {
                        formattedArg = FormatFunctionPointer(arg.ptrValue);
                    }
                    else {
                        formattedArg = FormatPointer(arg.ptrValue);
                    }
                }
                break;
            }

            case 'n':
                break;

            default:
                formattedArg = std::string("%") + specifier;
                break;
            }

            // 应用宽度对齐和填充
            if (width > 0 && static_cast<int>(formattedArg.length()) < width) {
                const int pad = width - static_cast<int>(formattedArg.length());
                if (leftAlign) {
                    formattedArg.append(pad, ' ');
                }
                else {
                    if (zeroPad) {
                        const size_t signPos = formattedArg.find_first_of("+-");
                        if (signPos != std::string::npos) {
                            formattedArg.insert(signPos + 1, pad, '0');
                        }
                        else {
                            formattedArg.insert(0, pad, '0');
                        }
                    }
                    else {
                        formattedArg.insert(0, pad, ' ');
                    }
                }
            }

            result += formattedArg;
        }
        else {
            result += *ptr++;
        }
    }

    return result;
}

std::string Logger::FormatChar(char c) {
    return std::string(1, c);
}

std::string Logger::FormatWideChar(wchar_t wc) {
    wchar_t wstr[2] = { wc, L'\0' };
    return EscapeSpecialCharacters(StringUtils::WideCharToUTF8(wstr));
}

std::string Logger::FormatInteger(int64_t value, int width, bool zeroPad, bool showSign, bool spaceSign) {
    char buffer[32];
    if (showSign && value >= 0) {
        snprintf(buffer, sizeof(buffer), "+%" PRId64, value);
    }
    else if (spaceSign && value >= 0) {
        snprintf(buffer, sizeof(buffer), " %" PRId64, value);
    }
    else {
        snprintf(buffer, sizeof(buffer), "%" PRId64, value);
    }
    return buffer;
}

std::string Logger::FormatUnsigned(uint64_t value, int width, bool zeroPad) {
    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%" PRIu64, value);
    return buffer;
}

std::string Logger::FormatOctal(uint64_t value, int width, bool zeroPad, bool alternateForm) {
    char buffer[32];
    if (alternateForm && value != 0) {
        snprintf(buffer, sizeof(buffer), "0%" PRIo64, value);
    }
    else {
        snprintf(buffer, sizeof(buffer), "%" PRIo64, value);
    }
    return buffer;
}

std::string Logger::FormatHex(uint64_t value, int width, bool zeroPad, bool alternateForm, bool uppercase) {
    char buffer[32];
    if (alternateForm && value != 0) {
        snprintf(buffer, sizeof(buffer), uppercase ? "0X%" PRIX64 : "0x%" PRIx64, value);
    }
    else {
        snprintf(buffer, sizeof(buffer), uppercase ? "%" PRIX64 : "%" PRIx64, value);
    }
    return buffer;
}

std::string Logger::FormatFloat(double value, int precision, int width, bool zeroPad, bool showSign, bool spaceSign) {
    std::ostringstream oss;
    oss << std::fixed;
    if (precision >= 0) {
        oss << std::setprecision(precision);
    }
    else {
        oss << std::setprecision(6);
    }

    if (value >= 0) {
        if (showSign) oss << '+';
        else if (spaceSign) oss << ' ';
    }
    oss << value;
    return oss.str();
}

std::string Logger::FormatScientific(double value, int precision, int width, bool zeroPad, bool showSign, bool spaceSign, bool uppercase) {
    std::ostringstream oss;
    if (uppercase) {
        oss << std::uppercase << std::scientific;
    }
    else {
        oss << std::scientific;
    }

    if (precision >= 0) {
        oss << std::setprecision(precision);
    }
    else {
        oss << std::setprecision(6);
    }

    if (value >= 0) {
        if (showSign) oss << '+';
        else if (spaceSign) oss << ' ';
    }
    oss << value;
    return oss.str();
}

std::string Logger::FormatGeneral(double value, int precision, int width, bool zeroPad, bool showSign, bool spaceSign, bool uppercase) {
    std::ostringstream oss;
    if (uppercase) oss << std::uppercase;

    if (precision >= 0) {
        oss << std::setprecision(precision);
    }
    else {
        oss << std::setprecision(6);
    }

    if (value >= 0) {
        if (showSign) oss << '+';
        else if (spaceSign) oss << ' ';
    }

    const double absValue = std::fabs(value);
    if (absValue > 1e-4 && absValue < 1e6) {
        oss << std::fixed << value;
    }
    else {
        oss << std::scientific << value;
    }
    return oss.str();
}

std::string Logger::FormatPointer(void* ptr) {
    if (ptr == nullptr) return "nullptr";

    char buffer[32];
#ifdef _WIN64
    snprintf(buffer, sizeof(buffer), "0x%llX", reinterpret_cast<uintptr_t>(ptr));
#else
    snprintf(buffer, sizeof(buffer), "0x%X", reinterpret_cast<uintptr_t>(ptr));
#endif
    return buffer;
}

std::string Logger::FormatFunctionPointer(void* funcPtr) {
    if (funcPtr == nullptr) return "nullptr";

    return FormatPointer(funcPtr);
}

std::string Logger::HexDump(const void* data, size_t len, bool compact) {
    if (!data || len == 0) return {};

    const auto* bytes = static_cast<const uint8_t*>(data);
    std::string result;
    result.reserve(compact ? len * 2 : len * 3);

    constexpr char hexDigits[] = "0123456789ABCDEF";

    for (size_t i = 0; i < len; ++i) {
        if (!compact && i > 0 && (i % 16 == 0)) {
            result += '\n';
        }
        else if (!compact && i > 0) {
            result += ' ';
        }

        result += hexDigits[bytes[i] >> 4];
        result += hexDigits[bytes[i] & 0x0F];
    }

    return result;
}

std::string Logger::HexDump(const std::string& str, bool compact) {
    return HexDump(str.data(), str.size(), compact);
}

std::string Logger::HexDump(const char* str, bool compact) {
    return str ? HexDump(str, std::strlen(str), compact) : std::string{};
}

std::string Logger::HexDump(const std::wstring& wstr, bool compact) {
    return HexDump(wstr.data(), wstr.size() * sizeof(wchar_t), compact);
}

std::string Logger::HexDump(const wchar_t* wstr, bool compact) {
    return wstr ? HexDump(wstr, std::wcslen(wstr) * sizeof(wchar_t), compact) : std::string{};
}
#endif
